// draw tree class functions start :/
import {minDistance, scaleFactorX, scaleFactorY} from "./Const";

export class Tree {
    constructor(node = 0, left=undefined, right=undefined, label = "", parent=undefined) {
        this.type = "Tree";
        this.id = -1;
        this.node = node;
        this.label = label;
        this.width = node.length;
        this.left = left;
        this.right = right;
        this.parent = parent;
    }
    

    getNode = () => {
        return this.node;
    }

    setId = (id) => {
        this.id = id;
    }

    getId = (id) => this.id;

    getType = () => this.type;
}

export class DrawTree {
    constructor(tree, parent = undefined, depth = 0) {
        this.type = "DrawTree";

        this.parent = parent;
        this.x = -1;
        this.y = depth;
        this.tree = tree;

        this.id = this.getId();
        this.node = this.getNode();
        this.isLeaf = false;
        this.left = undefined;
        this.right = undefined;
        this.mod = 0;
        this.thread = undefined;
        if (tree.left) {
            let newTree = new DrawTree(tree.left, this, depth + 1);
            this.left = newTree;
        }
        if (tree.right) {
            let newTree = new DrawTree(tree.right, this, depth + 1);
            this.right = newTree;
        }

    }


    getNode = () => this.tree.getNode();
    setId = (id) => {
        this.id = id;
    }
    getType = () => this.type;
    getId = () => this.tree.getId();


    getMostLeft = (node) => {
        if (!node.left) {
            return node;
        }
        return this.getMostLeft(node.left);
    }

    getMostRight = (node) => {
        if (!node.right) {
            return node;
        }
        return this.getMostRight(node.right);
    }

    getMostY = (node) => {
        let left = node.left;
        let right = node.right;
        let leftY = 0;
        let rightY = 0;
        if (left) {
             leftY = this.getMostY(left);
        }
        if (right) {
            rightY = this.getMostY(right);
        }
        if (!left && !right) {
            return node.y;
        }
        return leftY > rightY ? leftY : rightY;
    }
    
   

    toString = () => {
        return this.tree.label;
    }
}

function layout(tree) {
    setup(tree);
    addmods(tree);
    // scale(tree);
    return tree;
}

function nextright(tree) {
    if (tree.thread) {
        return tree.thread;
    }
    if (tree.right) {
        return tree.right;
    }
    return undefined;
}


function nextleft(tree) {
    if (tree.thread) {
        return tree.thread;
    }
    if (tree.left) {
        return tree.left;
    }
    return undefined;
}



function contour(left, right, max_offset=undefined, loffset=0, roffset=0, left_outer=undefined, right_outer=undefined) {
    let delta = left.x + loffset - (right.x + roffset);
    if (!max_offset || delta > max_offset) {
        max_offset = delta;
    }
    if (!left_outer) {
        left_outer = left;
    }
    if (!right_outer) {
        right_outer = right;
    }
    let lo = nextleft(left_outer);
    let li = nextright(left);
    let ri = nextleft(right);
    let ro = nextright(right_outer);

    if (li && ri) {
        loffset += left.mod;
        roffset += right.mod;
        return contour(li, ri, max_offset, loffset, roffset, lo, ro);
    }

     return [li, ri, max_offset, loffset, roffset, left_outer, right_outer];
}


function fix_subtrees(left, right) {
    let [li, ri, diff, loffset, roffset, lo, ro] = contour(left, right);
    diff += minDistance;
    // diff += (right.x + diff + left.x) % 2;
    right.mod = diff;
    right.x += diff;
    if (right.left || right.right) {
        roffset += diff;
    }

    if (ri && !li) {
        lo.thread = ri;
        lo.mod = roffset - loffset;
    } else if (li && !ri) {
        ro.thread = li;
        ro.mod = loffset - roffset;
    }
    return (left.x + right.x) / 2;

}
function setup(tree, depth=0) {
    if (!tree.left && !tree.right) {
        tree.x = 0;
        tree.isLeaf = true;
        return tree;
    }

    if (!(tree.left && tree.right)) {
        if (tree.left) {
            tree.x = setup(tree.left, depth + 1).x + minDistance;
            // tree.x = setup(tree.left, depth + 1).x;
        } else {
            tree.x = setup(tree.right, depth + 1).x - minDistance;
            // tree.x = setup(tree.right, depth + 1).x;
        }
        return tree;
    }
    
    let left = setup(tree.left, depth + 1);
    let right = setup(tree.right, depth + 1);
    tree.x = fix_subtrees(left, right);
    return tree;
}

function addmods(tree, modSum=0) {
    tree.x = tree.x + modSum;
    modSum += tree.mod;
    if (tree.left) {
        addmods(tree.left, modSum);
    } 
    if (tree.right) {
        addmods(tree.right, modSum);
    }
    
}


export function buchheim(tree) {

    let newTree = layout(new DrawTree(tree));
    console.log("newtree:")
    console.log( newTree)
    return newTree;
}


function print(newTree) {
    let queue = [];
    queue.push(newTree);
    let id = 0;
    while (queue.length !== 0) {
        if (queue[0].left) {
            queue.push(queue[0].left);
        }
        if (queue[0].right) {
            queue.push(queue[0].right);
        }
    queue.splice(0, 1);
}
}

let create = () => {
     let tree = new Tree(0,undefined, undefined,0+"");
     tree.right = new Tree(1, undefined, undefined, 1 + "");
     return tree;
}

let newTree = buchheim(create());


print(newTree)

